//macro to add histogram files
//NOTE: This macro is kept for back compatibility only.
//Use instead the executable $ROOTSYS/bin/hadd
//
//This macro will add histograms from a list of root files and write them
//to a target root file. The target file is newly created and must not be
//identical to one of the source files.
//
//Author: Sven A. Schmidt, sven.schmidt@cern.ch
//Date:   13.2.2001

//This code is based on the hadd.C example by Rene Brun and Dirk Geppert,
//which had a problem with directories more than one level deep.
//(see macro hadd_old.C for this previous implementation).
//
//The macro from Sven has been enhanced by
//   Anne-Sylvie Nicollerat <Anne-Sylvie.Nicollerat@cern.ch>
// to automatically add Trees (via a chain of trees).
//
//To use this macro, modify the file names in function hadd.
//
//NB: This macro is provided as a tutorial.
//    Use $ROOTSYS/bin/hadd to merge many histogram files



#include <string.h>
#include "TChain.h"
#include "TFile.h"
#include "TH1.h"
#include "TTree.h"
#include "TKey.h"
#include "Riostream.h"
#include "functions.h"

TList *FileList;
TFile *Target;

void MergeRootfile( TDirectory *target, TList *sourcelist );


void merger(TString input="list.txt", TString outfilename="out.root") {
   // in an interactive ROOT on, edit the file names
   // Target and FileList, then
   // root > .L hadd.C
   // root > merger()

   Target = TFile::Open( outfilename, "RECREATE" );

   FileList = new TList();
int num;
char ** files = new char *[300];
Readinput(input.Data(),files,num);

for (int i=0; i<num;i++)
{

   FileList->Add(TFile::Open(files[i]));
}
   MergeRootfile( Target, FileList );

}

void MergeRootfile( TDirectory *target, TList *sourcelist ) {

   //  cout << "Target path: " << target->GetPath() << endl;
   TString path( (char*)strstr( target->GetPath(), ":" ) );
   path.Remove( 0, 2 );

   TFile *first_source = (TFile*)sourcelist->First();
   first_source->cd( path );
   TDirectory *current_sourcedir = gDirectory;
   //gain time, do not add the objects in the list in memory
   Bool_t status = TH1::AddDirectoryStatus();
   TH1::AddDirectory(kFALSE);

   // loop over all keys in this directory
   TChain *globChain = 0;
   TIter nextkey( current_sourcedir->GetListOfKeys() );
   TKey *key, *oldkey=0;
   while ( (key = (TKey*)nextkey())) {

      //keep only the highest cycle number for each key
      if (oldkey && !strcmp(oldkey->GetName(),key->GetName())) continue;

      // read object from first source file
      first_source->cd( path );
      TObject *obj = key->ReadObj();

      if ( obj->IsA()->InheritsFrom( TH1::Class() ) ) {
         // descendant of TH1 -> merge it

         //      cout << "Merging histogram " << obj->GetName() << endl;
         TH1 *h1 = (TH1*)obj;

         // loop over all source files and add the content of the
         // correspondant histogram to the one pointed to by "h1"
         TFile *nextsource = (TFile*)sourcelist->After( first_source );
         while ( nextsource ) {

            // make sure we are at the correct directory level by cd'ing to path
            nextsource->cd( path );
            TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(h1->GetName());
            if (key2) {
               TH1 *h2 = (TH1*)key2->ReadObj();
               h1->Add( h2 );
               delete h2;
            }

            nextsource = (TFile*)sourcelist->After( nextsource );
         }
      }
      else if ( obj->IsA()->InheritsFrom( TTree::Class() ) ) {

         // loop over all source files create a chain of Trees "globChain"
         const char* obj_name= obj->GetName();

         globChain = new TChain(obj_name);
         globChain->Add(first_source->GetName());
         TFile *nextsource = (TFile*)sourcelist->After( first_source );
         //      const char* file_name = nextsource->GetName();
         // cout << "file name  " << file_name << endl;
         while ( nextsource ) {

            globChain->Add(nextsource->GetName());
            nextsource = (TFile*)sourcelist->After( nextsource );
         }

      } else if ( obj->IsA()->InheritsFrom( TDirectory::Class() ) ) {
         // it's a subdirectory

         cout << "Found subdirectory " << obj->GetName() << endl;

         // create a new subdir of same name and title in the target file
         target->cd();
         TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );

         // newdir is now the starting point of another round of merging
         // newdir still knows its depth within the target file via
         // GetPath(), so we can still figure out where we are in the recursion
         MergeRootfile( newdir, sourcelist );

} else if ( obj->IsA()->InheritsFrom( TDirectoryFile::Class() ) ) {
         // it's a subdirectory

         cout << "Found subdirectory " << obj->GetName() << endl;

         // create a new subdir of same name and title in the target file
         target->cd();
         TDirectory *newdir = target->mkdir( obj->GetName(), obj->GetTitle() );

         // newdir is now the starting point of another round of merging
         // newdir still knows its depth within the target file via
         // GetPath(), so we can still figure out where we are in the recursion
         MergeRootfile( newdir, sourcelist );


      } 
else if (obj->IsA()->InheritsFrom( Selection::Class() )  ){
         // object is of no type that we know or can handle
         cout << "object type, name: "
          <<"Selection," << obj->GetName() << " title: " << obj->GetTitle() << endl;
	Selection *sel1 = (Selection*)obj;
         // loop over all source files and add the content of the
         // correspondant histogram to the one pointed to by "h1"
         TFile *nextsource = (TFile*)sourcelist->After( first_source );
	TList *addList= new TList();
         while ( nextsource ) {
            // make sure we are at the correct directory level by cd'ing to path
            nextsource->cd( path );
            TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(sel1->GetName());
            if (key2) {
               Selection *sel2 = (Selection*)key2->ReadObj();
               if (sel2) 		addList->Add( sel2 );
     		}
            nextsource = (TFile*)sourcelist->After( nextsource );
         }
	sel1->Merge(addList);
	delete addList;
	
      }	

else if (obj->IsA()->InheritsFrom( Sample::Class() )  ){
         // object is of no type that we know or can handle
         cout << "object type, name: "
          <<"Sample," << obj->GetName() << " title: " << obj->GetTitle() << endl;
	Sample *smp1 = (Sample*)obj;
         // loop over all source files and add the content of the
         // correspondant histogram to the one pointed to by "h1"
         TFile *nextsource = (TFile*)sourcelist->After( first_source );
	TList *addList= new TList();
         while ( nextsource ) {
            // make sure we are at the correct directory level by cd'ing to path
            nextsource->cd( path );
            TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(smp1->GetName());
            if (key2) {
               Sample *smp2 = (Sample*)key2->ReadObj();
               if (smp2) 		addList->Add( smp2 );
     		}
            nextsource = (TFile*)sourcelist->After( nextsource );
         }
	smp1->Merge(addList);
	delete addList;
	
      }	

 else if (obj->IsA()->InheritsFrom( Counter::Class() )  ){
         // object is of no type that we know or can handle
         cout << "object type, name: "
          <<"Counter," << obj->GetName() << " title: " << obj->GetTitle() << endl;
	Counter *cnt1 = (Counter*)obj;
         // loop over all source files and add the content of the
         // correspondant histogram to the one pointed to by "h1"
         TFile *nextsource = (TFile*)sourcelist->After( first_source );
	cout <<"File "<<first_source->GetName()<<" has "<<cnt1->getEvents()<<" events"<<endl;
	TList *addList= new TList();
         while ( nextsource ) {
            // make sure we are at the correct directory level by cd'ing to path
            nextsource->cd( path );
            TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(cnt1->GetName());
            if (key2) {
               Counter *cnt2 = (Counter*)key2->ReadObj();
               if (cnt2) 		addList->Add(cnt2 );
	       if (cnt2)   cout <<"File "<<nextsource->GetName()<<" has "<<cnt2->getEvents()<<" events"<<endl;

     		}
//	       const char* file_name = nextsource->GetName();
//         cout << "file name  " << file_name << endl;
            nextsource = (TFile*)sourcelist->After( nextsource );
//		cnt1->Merge(addList);
//		addList->Clear();

         }
		cnt1->Merge(addList);

	delete addList;
	
      }	

	else if (obj->IsA()->InheritsFrom( Header::Class() )  ){
         // object is of no type that we know or can handle
         cout << "object type, name: "
          <<"Header," << obj->GetName() << " title: " << obj->GetTitle() << endl;
        Header *hdr1 = (Header*)obj;
         // loop over all source files and add the content of the
         // correspondant histogram to the one pointed to by "h1"
         TFile *nextsource = (TFile*)sourcelist->After( first_source );
        TList *addList= new TList();
         while ( nextsource ) {
            // make sure we are at the correct directory level by cd'ing to path
            nextsource->cd( path );
            TKey *key2 = (TKey*)gDirectory->GetListOfKeys()->FindObject(hdr1->GetName());
            if (key2) {
               Header *hdr2 = (Header*)key2->ReadObj();
               if (hdr2)                 addList->Add( hdr2 );
                }
            nextsource = (TFile*)sourcelist->After( nextsource );
	//        hdr1->Merge(addList);
	//	addList->Clear();


         }
	        hdr1->Merge(addList);

        delete addList;

      }


      // now write the merged histogram (which is "in" obj) to the target file
      // note that this will just store obj in the current directory level,
      // which is not persistent until the complete directory itself is stored
      // by "target->Write()" below
      if ( obj ) {
         target->cd();

         //!!if the object is a tree, it is stored in globChain...
         if(obj->IsA()->InheritsFrom( TTree::Class() ))
            globChain->Merge(target->GetFile(),0,"keep");
         else
            obj->Write( key->GetName() );
      }

   } // while ( ( TKey *key = (TKey*)nextkey() ) )

   // save modifications to target file
   target->SaveSelf(kTRUE);
   TH1::AddDirectory(status);
}


